package com.pbdemo.config;

import com.google.protobuf.MessageLite;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import xyz.noark.core.exception.DataException;
import xyz.noark.core.exception.UnrealizedException;
import xyz.noark.core.lang.ByteArray;
import xyz.noark.core.lang.ByteArrayOutputStream;
import xyz.noark.core.lang.ImmutableByteArray;
import xyz.noark.core.network.NetworkPacket;
import xyz.noark.core.network.NetworkProtocol;
import xyz.noark.core.util.UnsignedUtils;
import xyz.noark.network.codec.ByteBufWrapper;
import xyz.noark.network.codec.DefaultNetworkPacket;
import xyz.noark.network.codec.protobuf.ProtobufCodec;

import java.io.IOException;

public class Codec extends ProtobufCodec {


    @Override
    public ByteArray encodePacket(NetworkProtocol networkProtocol) {
        final int opcode = (Integer) networkProtocol.getOpcode();
        if (opcode > Short.MAX_VALUE) {
            throw new UnrealizedException("illegal opcode=" + opcode + ", max=65535");
        }

        MessageLite message;
        if (networkProtocol.getProtocol() instanceof MessageLite) {
            message = (MessageLite) networkProtocol.getProtocol();
        } else if (networkProtocol.getProtocol() instanceof MessageLite.Builder) {
            message = ((MessageLite.Builder) networkProtocol.getProtocol()).build();
        } else {
            throw new UnrealizedException("illegal data type：" + networkProtocol.getProtocol().getClass());
        }

        ImmutableByteArray byteArray = new ImmutableByteArray(message.getSerializedSize() + 2);
        try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(byteArray)) {
            // 写入Opcode
            byteArrayOutputStream.writeShort(opcode);
            // 写入协议内容
            try {
                message.writeTo(byteArrayOutputStream);
            } catch (IOException e) {
                throw new DataException("PB writeTo exception", e);
            }
            return byteArray;
        }
    }

    @Override
    public MessageToByteEncoder<?> lengthEncoder() {
        return new PbLengthEncoder();
    }

    @Override
    public ByteToMessageDecoder lengthDecoder() {
        return new PbLengthDecoder(this);
    }

    @Override
    public NetworkPacket decodePacket(ByteBuf byteBuf) {
        DefaultNetworkPacket packet = new DefaultNetworkPacket();
        packet.setLength(byteBuf.readableBytes());
//        packet.setIncode(UnsignedUtils.toUnsigned(byteBuf.readShort()));
//        packet.setChecksum(UnsignedUtils.toUnsigned(byteBuf.readShort()));
        packet.setOpcode(UnsignedUtils.toUnsigned(byteBuf.readShort()));
        packet.setBytes(new ByteBufWrapper(byteBuf));
        return packet;
    }
}
